/*BOXD为接线盒数字型，由宫老师开发。
BOXD和DT45数字型之间通过RS485相连，协议为modbus-rtu，BOXD为主机，提供各种寄存器。
RS485为DT45D的USART3。
*/
#include <stdio.h>
#include <string.h>

#include "stm32l4xx.h"
#include "stm32l4xx_ll_bus.h"
#include "stm32l4xx_ll_rcc.h"
#include "stm32l4xx_ll_gpio.h"
#include "stm32l4xx_ll_lpuart.h"
#include "stm32l4xx_ll_usart.h"

#include "bsp_uart_ble.h"		//没什么用处。
#include "bsp_modbus.h"
#include "bsp.h"
#include "parameter.h"
#include "dbgUart.h"

extern DBGUART dbgUart;

//#define MODE_7_E_1								0
//#define MODE_7_O_1								1
//#define MODE_8_E_1								2
//#define MODE_8_O_1								3
//#define MODE_8_n_1								4
//#define MODE_8_n_2								5


const uint32_t tbl_baud_ble[]={/*1200,4800,*/9600,19200,38400,57600,115200, 0};
const char* tbl_fmt_ble[]={/*" 7-E-1", " 7-O-1",*/  " 8-n-2", " 8-O-1", " 8-E-1", " 8-n-1", ""};

void BLE_UART_Tx1st(void);


UART_CFG2 uart_to_ble_cfg={9600, FMT_8_E_1, 0};


/*设置RS485的串口模式，波特率和当前状态。
*/
void bsp_uart_ble_config(const char* fmt, uint32_t baud, uint8_t sta)
{
	uint32_t pclk1_clock;
	uint32_t baud_rate;
	
	
	baud_rate= baud;		

	
	if(baud_rate< 19200){	
		//使能HSI，并等待稳定。
		LL_RCC_HSI_Enable();
		while(0 == LL_RCC_HSI_IsReady()){}	//不能使用LL_RCC_IsActiveFlag_HSIRDY()。
			
		LL_RCC_SetUSARTClockSource(LL_RCC_USART2_CLKSOURCE_HSI);
		pclk1_clock= 16000000;	//没找到更合适的函数，暂直接指定值。
	}
	else{
		LL_RCC_SetUSARTClockSource(LL_RCC_USART2_CLKSOURCE_SYSCLK);
		pclk1_clock= 48000000;
	}
	
	pclk1_clock= LL_RCC_GetUSARTClockFreq(LL_RCC_USART2_CLKSOURCE);
	LL_USART_SetBaudRate(UART_BLE, pclk1_clock, 0, baud_rate);	//第3个参数是OverSampling。 QQ可以在USART使能时，更改波特率吗？

	
	if(0 != uart_to_ble_cfg.sta){
		//先将USART3关闭。
		LL_USART_Disable(UART_BLE);
	}
	
	
	if(0){
	}
	else if(0 == strcmp(fmt, FMT_8_E_1)){
		LL_USART_ConfigCharacter(UART_BLE, LL_USART_DATAWIDTH_9B, LL_USART_PARITY_EVEN, LL_USART_STOPBITS_1);	//奇偶校验时，数据宽度须为9B。
	}
	else if(0 == strcmp(fmt, FMT_8_O_1)){
		LL_USART_ConfigCharacter(UART_BLE, LL_USART_DATAWIDTH_9B, LL_USART_PARITY_EVEN, LL_USART_STOPBITS_1);	//奇偶校验时，数据宽度须为9B。
	}
	else if(0 == strcmp(fmt, FMT_8_n_1)){
		LL_USART_ConfigCharacter(UART_BLE, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_1);
	}
	else if(0 == strcmp(fmt, FMT_8_n_2)){
		LL_USART_ConfigCharacter(UART_BLE, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_2);
	}
	else{	//FMT_8_L_1...
		LL_USART_ConfigCharacter(UART_BLE, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_1);
	}
	
	
	if(0 == sta){
		//先将USART3关闭。
		LL_USART_Enable(UART_BLE);
	}
	
	//RS485_BOXD_RX;
	
	//根据波特率，设定接收超时时间（暂统一）
	modbus_recv_info_ble.tmo_max= 10;	//原值为100ms
}



static void bsp_uart_ble_hal(void)
{
	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

	/*
	TX		Pin16/PA2	USART2。
	RX		Pin17/PA3	USART2。
	*/
	LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_2, LL_GPIO_MODE_ALTERNATE);
	LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_2, LL_GPIO_AF_7);				//C AF7 as USART2_TX.
	
	LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_3, LL_GPIO_PULL_UP);
	LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_3, LL_GPIO_MODE_ALTERNATE);
	LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_3, LL_GPIO_AF_7);				//C AF7 as USART2_RX.
}



/*配置MCU和BOXD盒相连的串口。
!!需要开启相应时钟。
!!115200用11520标示。
*/
void bsp_uart_ble_init(uint32_t baud, const char* fmt)
{
	bsp_uart_ble_hal();
	
	LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2);
	//LL_RCC_SetUSARTClockSource(LL_RCC_USART3_CLKSOURCE_SYSCLK);		//PCLK as USART1's clock source,!!Must enable USART1_EN@RCC_APB1ENR1.
	
	LL_USART_Disable(UART_BLE);	//因为会动态修改该串口参数，所以假定它处于使能状态，需先禁止。
	
	/*配置串口：中断接收，查询发送。
	帧格式：
	0：无校验：2位停止位
	1：奇校验，1位停止位；
	2：偶校验，1位停止位；
	3：无校验，1位停止位；
	波特率：
	0  9600");
	1  19200");
	2  38400");
	3  57600");
	4  115200");
	*/
	uart_to_ble_cfg.baud= baud;
	strcpy(uart_to_ble_cfg.fmt, fmt);
	uart_to_ble_cfg.sta= 0;
	
	//C OVER8@CR1=0, 16 samples.
	/* baudrate= fck/(8*(2-OVER8)*UARTDIV). UARTDIV= man.fra.
	例fpclk=84MHz，16samples，115200时，man.fra=45.5625，即0x2D9。
	具体参考RM0090's P978。
	*/
	bsp_uart_ble_config(uart_to_ble_cfg.fmt, uart_to_ble_cfg.baud, 0);	//9600/19200/38400/57600

	
	LL_USART_EnableDirectionTx(UART_BLE);
	LL_USART_EnableDirectionRx(UART_BLE);
	LL_USART_Enable(UART_BLE);
	
	LL_USART_EnableIT_RXNE(UART_BLE);
	
	
	/* preemption = 1, sub-priority = 1 */
	NVIC_SetPriority(UART_BLE_IRQn, 1);
	/* Enable Interrupt for UART0 channel */
	NVIC_EnableIRQ(UART_BLE_IRQn);
}



/*配置BLE串口做调试串口。固定为11520，8-n-1。
*/
void BLE_initUart(uint32_t baud)
{
	bsp_uart_ble_hal();
	
	LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2);
	//LL_RCC_SetUSARTClockSource(LL_RCC_USART3_CLKSOURCE_SYSCLK);		//PCLK as USART1's clock source,!!Must enable USART1_EN@RCC_APB1ENR1.
	
	LL_USART_Disable(UART_BLE);	//因为会动态修改该串口参数，所以假定它处于使能状态，需先禁止。
	
	/*配置串口：中断接收，查询发送。
	帧格式：
	0：无校验：2位停止位
	1：奇校验，1位停止位；
	2：偶校验，1位停止位；
	3：无校验，1位停止位；
	波特率：
	0  9600");
	1  19200");
	2  38400");
	3  57600");
	4  115200");
	*/
	uart_to_ble_cfg.baud= baud;
	strcpy(uart_to_ble_cfg.fmt, FMT_8_n_1);
	uart_to_ble_cfg.sta= 0;
	
	//C OVER8@CR1=0, 16 samples.
	/* baudrate= fck/(8*(2-OVER8)*UARTDIV). UARTDIV= man.fra.
	例fpclk=84MHz，16samples，115200时，man.fra=45.5625，即0x2D9。
	具体参考RM0090's P978。
	*/
	bsp_uart_ble_config(uart_to_ble_cfg.fmt, uart_to_ble_cfg.baud, 0);	//9600/19200/38400/57600
	
	
	LL_USART_EnableDirectionTx(UART_BLE);
	LL_USART_EnableDirectionRx(UART_BLE);
	LL_USART_Enable(UART_BLE);			//QQ这个应该放在最后更合适？
	
	LL_USART_EnableIT_RXNE(UART_BLE);
	
	
	/* preemption = 1, sub-priority = 1 */
	NVIC_SetPriority(UART_BLE_IRQn, 1);
	/* Enable Interrupt for UART0 channel */
	NVIC_EnableIRQ(UART_BLE_IRQn);
}



//C Func: put bytes to Uart0TxFIFO, the length is Length. If the Uart0TxFIFO has enought space to contain data, return 1.
//C       other, return 0.
//C return: uchRet, 1---成功放入UartTxFIFO, 0---放入失败。
uint8_t BLE_UART_TxDataBuf(uint8_t const *pStr, uint16_t Length)
{
	uint16_t i = 0, lastcnt = 0;	//C the size to be used to contain data.
	uint8_t uchRet = 0;

	
	dbgUart.OutIdxBk= dbgUart.OutIndex;		//C 获取OutIndex的副本。因为OutIndex可能会改变。
	
	//C lastcnt:
	if(dbgUart.InIndex >= dbgUart.OutIdxBk)
		lastcnt = (UART_TX_FIFO_DEPTH - 1)
			- (dbgUart.InIndex - dbgUart.OutIdxBk) ;

	if(dbgUart.OutIdxBk > dbgUart.InIndex)
		lastcnt = (UART_TX_FIFO_DEPTH - 1)
			- (dbgUart.OutIdxBk - dbgUart.InIndex) ;

	if (lastcnt >= Length){  //C UartTxFIFO容得下待发送的数据。
	
		for (i = 0; i < Length; i++){
		
			dbgUart.TxFIFO[dbgUart.InIndex] = pStr[i];
			dbgUart.InIndex++;
			dbgUart.InIndex &= (UART_TX_FIFO_DEPTH - 1);
		}
		uchRet = 1;
	}
	else{	//C UartTxFIFO容不下待发送的数据。
	
		dbgUart.TxFIFO[dbgUart.InIndex] = '?';	//C old value is 0xFF, change to '?'
		dbgUart.InIndex++;
		dbgUart.InIndex &= (UART_TX_FIFO_DEPTH - 1);
		uchRet = 0;
	}

	
	__ASM volatile("cpsid i");
	
	if(0 == dbgUart.flagTxing)
		BLE_UART_Tx1st();	//C 当前不是Txing，则开启发送。

	__ASM volatile ("cpsie i");
	
	return uchRet;
}




/*写入串口的发送寄存器。
*/
void BLE_wrTHR(uint32_t data)
{
	//DBG_UART->TDR= data;
	LL_USART_TransmitData8(UART_BLE, data);
}



/*使能/禁能串口的发送中断（THRE）
*/
void BLE_intTHR(uint32_t sta)
{
	if(0 == sta){
		//DBG_UART->CR1 &= ~(1UL<< 7);
		LL_USART_DisableIT_TXE(UART_BLE);
	}
	else{
		//DBG_UART->CR1 |= (1UL<< 7);
		LL_USART_EnableIT_TXE(UART_BLE);
	}
}



void BLE_UART_Tx1st(void)
{
	if(dbgUart.InIndex != dbgUart.OutIndex){	//C TxFIFO不空。
		
		dbgUart.wrTHR(dbgUart.TxFIFO[dbgUart.OutIndex]);
		dbgUart.OutIndex++;
		dbgUart.OutIndex &= (UART_TX_FIFO_DEPTH- 1);
		
		dbgUart.flagTxing= 1;
		
		dbgUart.intTHR(1);	//C 使能TX发送中断。
	}
}



/*串口发送中断处理函数。
当进入发送中断，说明THR空（即FIFO、THR都空），可写入最多17B（THR+16FIFO）。实测写入17丢输出。
*/
void BLE_UART_TxInt(void)
{
	uint8_t tmp;
	

	tmp= dbgUart.hwFIFOcnt;
	while(tmp){	//C max 16B write to THR FIFO. 如果写了少于16B，之后关闭IER。放心,串口仍会发送。
	
		tmp--;
		
		if( dbgUart.OutIndex != dbgUart.InIndex )
		{
			dbgUart.wrTHR(dbgUart.TxFIFO[dbgUart.OutIndex]);
			dbgUart.OutIndex++;
			dbgUart.OutIndex &= (UART_TX_FIFO_DEPTH- 1);
		}
		else{
		
			dbgUart.intTHR(0);		//C 关闭串口发送中断。
			dbgUart.flagTxing= 0;
			
			break;	//C jump out. maybe less than 16B.
		}
	}
}
/************************ END OF FILE ************************/






